import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;

public class ProducerConsumer {
	public static AtomicInteger total = new AtomicInteger();

	private static final int BOUND = 16;
	private static final int N_CONSUMERS = 8;

	public static void startComputation() {
		@SuppressWarnings("unchecked")
		BlockingDeque<Integer>[] dequeues = new BlockingDeque[N_CONSUMERS];

		for (int i = 0; i < dequeues.length; i++) {
			dequeues[i] = new LinkedBlockingDeque<Integer>(BOUND);
		}

		CountDownLatch producerLatch = new CountDownLatch(1);
		CountDownLatch consumerLatch = new CountDownLatch(1);

		AtomicInteger jobCounter = new AtomicInteger();

		int producerIndex = 0;
		Thread producer = new Thread(new Producer(dequeues, producerLatch,
				consumerLatch, jobCounter), "Producer-" + producerIndex);
		producerIndex++;
		producer.start();

		ExecutorService executorService = Executors.newFixedThreadPool(4);

		for (int i = 0; i < N_CONSUMERS; i++) {
			Consumer consumer = new Consumer(dequeues, i, executorService,
					consumerLatch, producerLatch, jobCounter);
			executorService.submit(consumer);
		}

		try {
			producerLatch.await();
			consumerLatch.await();
			executorService.shutdown();
			System.out.println("Total: " + total);
		} catch (InterruptedException e) {
			System.out.println("Was interrupted, while awaiting for latch.");
		}
	}
}